#ifndef __DALELIB_ALIFE_MLP_H__
#define __DALELIB_ALIFE_MLP_H__

//#include <dalelib/maths.h>
//#include <dalelib/graphics.h>
//#include <dalelib/utils/daleassert.h>
#include <vector>
#include <fstream>
using namespace std;

namespace dalelib
{

struct MLPNeuronLayer
{
	struct MLPNeuron
	{
		float _output;
		float _sum;
		float _error;
		float _bias;
	};

	vector<MLPNeuron> _neurons;
	MLPNeuronLayer(const int _Num)
	{
		_neurons.resize(_Num);
		for(int i=0; i<_Num; ++i)
		{
			_neurons[i]._output = 0.f;
			_neurons[i]._sum = 0.f;
			_neurons[i]._error = 0.f;
			_neurons[i]._bias = 0.f;
		}
	}

	MLPNeuront& operator[](const int _Index) { return _neurons[_Index]; }
};

struct MLPSynapseLayer
{
	vector<MLPNeuron> _weights;
	MLPSynapseLayer(const int _NumFrom,const int _NumTo)
	{
		_weights.resize(_NumFrom*_NumTo);
		for(int i=0; i<_NumFrom*_NumTo; ++i) _weights[i] = RAND;
	}

	float& operator[](const int _Index) { return _weights[_Index]; }
};


//**************************************************************
class MLP
{
public:

	typedef vector<MLPNeuronLayer> NeuronLayerList;
	typedef vector<MLPSynapseLayer> SynapseLayerList;

private:

	NeuronLayerList _neuronlayers;
	SynapseLayerList _synapselayers;

public:

	void addLayer(const int _NumNeurons)
	{
		_neuronlayers.push_back(MLPNeuronLayer(_NumNeurons));
		if(_neuronlayers.size()>1)
		{
			int prevnum = _neuronlayers[_neuronlayers.size()-1].size();
			_synapselayers.push_back(MLPSynapseLayer(prevnum,_NumNeurons));
		}
	}

	void feedForward()
	{
		for(unsigned int layer=0; layer<_neuronlayers.size(); ++layer)
		{
			if(i>0)
			{
				int fromneuronlayerindex = i-1;
				int toneuronlayerindex = i;
				int synapselayerindex = i-1;
				for(unsigned int w=0,i=0; i<_neuronlayers[toneuronlayerindex].size(); ++i)
				{
					_neuronlayers[toneuronlayerindex][i]._sum = _neuronlayers[toneuronlayerindex][i]._bias;
					for(unsigned int j=0; j<_neuronlayers[fromneuronlayerindex].size(); ++j,++w)
					{
						_neuronlayers[toneuronlayerindex][i]._sum += _neuronlayers[fromneuronlayerindex][j]._output*_synapselayers[synapselayerindex][w];
					}
					_neuronlayers[toneuronlayerindex][i]._output = 1.f/(1.f+exp(-_neuronlayers[toneuronlayerindex][i]._sum));
				}
			}
		}
	}

};

} // namespace dalelib

#endif // __DALELIB_ALIFE_CTRNN_H__
